package jwt

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"time"
)

type validator struct {
	secret      string
	algorithm   IAlgorithm
	headerPart  string
	payloadPart string
	signPart    string
}

func NewValidator(secret string, algorithm IAlgorithm) *validator {
	return &validator{
		secret:    secret,
		algorithm: algorithm,
	}
}

func (v *validator) SetSecret(secret string) *validator {
	v.secret = secret

	return v
}

func (v *validator) SetAlgorithm(algorithm IAlgorithm) *validator {
	v.algorithm = algorithm

	return v
}

func (v *validator) SetHeaderPart(headerPart string) *validator {
	v.headerPart = headerPart

	return v
}

func (v *validator) SetPayloadPart(payloadPart string) *validator {
	v.payloadPart = payloadPart

	return v
}

func (v *validator) SetSignPart(signPart string) *validator {
	v.signPart = signPart

	return v
}

func (v *validator) Verify(payload IPayload) (err error) {
	if nil == payload {
		return errors.New("payload is nil")
	}

	if nil == v.algorithm {
		return errors.New("algorithm is nil")
	}

	if "" == v.headerPart {
		return errors.New("headerPart is empty")
	}

	if "" == v.payloadPart {
		return errors.New("payloadPart is empty")
	}

	if "" == v.signPart {
		return errors.New("signPart is empty")
	}

	raw := fmt.Sprintf("%s.%s", v.headerPart, v.payloadPart)

	var access bool
	if access, err = v.algorithm.Verify(raw, v.signPart, v.secret); nil != err {
		return
	}

	if false == access {
		return errors.New("sign is not match")
	}

	var payloadBuf []byte
	if payloadBuf, err = base64.RawURLEncoding.DecodeString(v.payloadPart); nil != err {
		return
	}

	if err = json.Unmarshal(payloadBuf, payload); nil != err {
		return
	}

	if time.Now().Unix() > payload.GetExpired() {
		err = errors.New("token is expired")
	}

	return
}
